Google CalendarのUIを真似てCalendar UIを作る:<ul>と<li>で組んだver.
Google CalendarのUIを真似てCalendar UIを作る:<ul>と<li>で組んだver. これをヒントに、<ul>での組み立てを試みる
完成品
https://gyazo.com/4c2ff3520eba9012ab8c10f68c591854
.weekと.body > liにheight: 100%を入れてないと隙間ができてしまう (スクショなし)
ややDOMの階層が増えてしまうが、こちらのほうが階層構造がわかりやすいだろう
code:app.tsx
/** @jsx h */
import { h, render} from "../preact/mod.tsx";
import { Calendar } from "./ul.tsx";
const div = document.createElement("div");
const shadowRoot = div.attachShadow({ mode: "open" });
document.body.append(div);
// 消すときはカレンダーをクリックする
render(<Calendar onClose={() => div.remove()}/>, shadowRoot);
code:ul.tsx
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from "../preact/mod.tsx";
import { getAllDaysInCalendar } from "../getAllDaysInCalendar/mod.ts";
import { isToday, getWeek, getDate, getMonth } from "../date-fns/mod.ts";
export const Calendar = ({ onClose }) => {
const weeks = getAllDaysInCalendar(new Date());
const month = getMonth(new Date());
return (<>
<style>{`
:host {
position: fixed;
top: 10%;
left: 10%;
margin: 0 auto;
min-width: 30vw;
min-height: 50vh;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: inline-block;
}
.calendar-wrap {
position: absolute;
inset: 0;
outline: none;
overflow: hidden;
background-color: white;
height: 100%;
display: flex;
flex-direction: column;
--row-header-width: 24px;
--column-header-height: 20px;
.headers {
margin: 0;
height: var(--column-header-height);
display: flex;
flex: none;
align-items: stretch;
.corner {
position: relative;
top: calc(var(--column-header-height) / 2);
width: var(--row-header-width);
background-color: rgb(241,243,244);
border-top-left-radius: 4px;
border-top-right-radius: 4px
}
.column {
border-right: rgb(218,220,224) 1px solid;
flex: 1 1 0%;
text-align: center;
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
line-height: 20px;
}
}
.body {
margin: 0;
overflow: hidden;
flex: 1 1 0%;
display: flex;
flex-direction: column;
li {
height: 100%;
}
.week {
position: relative;
overflow: hidden;
border-bottom: rgb(218,220,224) 1px solid;
display: flex;
flex: 1 1 0%;
height: 100%;
.header {
width: var(--row-header-width);
padding-top: 8px;
text-align: center;
color: rgb(60,64,67);
font-size: 12px;
font-weight: 500;
letter-spacing: .3px;
line-height: 16px;
}
.row {
position: absolute;
inset: 0;
left: var(--row-header-width);
display: flex;
height: 100%;
.cell {
font-size: 14px;
line-height: 30px;
text-align: center;
background: transparent;
flex: 1 1 0%;
border-right: rgb(218,220,224) 1px solid;
overflow: hidden; /* セルの中身で大きさが変化しなくなる */
h2 {
margin-top: 8px;
font-size: 12px;
font-weight: 500;
letter-spacing: .3px;
display: inline-block;
text-align: center;
white-space: nowrap;
width: max-content;
min-width: 24px;
line-height: 16px;
pointer-events: auto;
}
}
.cell:last-child {
border-right: none;
}
}
}
}
}
`}</style>
<div className="calendar-wrap" onClick={onClose} role="grid">
<ul className="headers" role="row">
<li className="corner" />
(day) => (<li className="column" role="columnheader">{day}</li>)
)}
</ul>
<ul className="body" role="presentation">
{weeks.map((dates) => (<li><Week dates={dates} /></li>))}
</ul>
</div>
</>);
};
const Week = ({ dates }) => {
return (<ul className="week">
<li className="header" aria-hidden="true">{getWeek(dates0)}</li> <li><ul className="row" aria-hidden="true">
{dates.map((date) => (<li className="cell">
<h2>{getDate(date) !== 1 ? getDate(date) : ${getMonth(date)}月${getDate(date)}日}</h2>
</li>))}
</ul></li>
</ul>);
};